
#include "operacionesSectores.h"
#include "estructuras.h"
#include "operacionesFUSE.h"
#include "imprimir.h"
#include "utils.h"
#include "funcionesBasicas.h"
#include "capaDireccionamiento.h"
#include <stdio.h>
#include <stdint.h>//uintN_t N bits, http://linux.die.net/man/3/uint32_t
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>//manejar errores
#include <unistd.h>
#include <fcntl.h>//posix manejar archivos
#include <dirent.h>//posix manejar directorios
#include <sys/stat.h>

//****************************************************************************************************

void iniciarStructLfn(LFN *ptrLfn){

	memset(ptrLfn->nameLFN1,0,5);
	memset(ptrLfn->nameLFN2,0,6);
	memset(ptrLfn->nameLFN3,0,2);
	ptrLfn->attributes = 0;
	ptrLfn->firstCluster = 0;
	ptrLfn->sequenceNumber = 0;

}

void castEntryToLfn(uint8_t *entrada,LFN *ptrLfn){

	iniciarStructLfn(ptrLfn);
	uint8_t j;
	j = 1;
	memcpy(&(ptrLfn->nameLFN1),&entrada[j],10);
	j = 14;
	memcpy(&(ptrLfn->nameLFN2),&entrada[j],12);
	j = 28;
	memcpy(&(ptrLfn->nameLFN3),&entrada[j],4);
	ptrLfn->attributes = entrada[11];
	ptrLfn->checksum = entrada[13];

}

void castLfnToEntry(uint8_t *entrada,LFN *ptrLfn){

	uint8_t j;
	j = 1;
	memcpy(&entrada[j],(ptrLfn->nameLFN1),10);
	j = 14;
	memcpy(&entrada[j],&(ptrLfn->nameLFN2),12);
	j = 28;
	memcpy(&entrada[j],&(ptrLfn->nameLFN3),4);
}

char *armarNombreLFNaUTF8(LFN lfn){//uint8_t buffer[]){

	uint16_t buffer[13];
	memset(buffer,0,26);
	size_t tamUTF8;
	memcpy(buffer,lfn.nameLFN1,10);
	memcpy(&buffer[5],lfn.nameLFN2,12);
	memcpy(&buffer[11],lfn.nameLFN3,4);

	//for(uint8_t ind = 0; ind<13;ind++){printf("pos: %d: %d\n",ind,buffer[ind]);}

	char *utf8 = calloc(13,sizeof(char));
	unicode_utf16_to_utf8_inbuffer(buffer,13,utf8,&tamUTF8);
	//printf("cadena: %s \n",utf8);//***************************
	//free(buffer);
	return utf8;
}

void armarNombreLFNaUTF16(const char *utf8,uint16_t *utf16){//uint8_t buffer[]){

	size_t tamUTF16;
	//uint16_t *utf16 = calloc(13,sizeof(uint16_t));
	//unicode_utf16_to_utf8_inbuffer(buffer,13,utf16,&tamUTF16);
	unicode_utf8_to_utf16_inbuffer(utf8,13,utf16,&tamUTF16);
	//printf("cadena: %s \n",utf16);//***************************
	//free(buffer);
	//return utf16;
}

void modificarLfn(LFN *ptrLfn,uint16_t *newName){

	memset(ptrLfn->nameLFN1,0,10);
	memset(ptrLfn->nameLFN2,0,12);
	memset(ptrLfn->nameLFN3,0,4);
	memcpy(ptrLfn->nameLFN1,newName,10);
	memcpy(ptrLfn->nameLFN2,&newName[5],10);
	memcpy(ptrLfn->nameLFN3,&newName[11],10);
}

void eliminarLFN(UbicacionCache ubicacion){

	if( ubicacion.nroByte != 300){
	uint8_t offset;
	offset = 0x0B;
	capaDir.sectores[ubicacion.nroSectorEntradaSgte].bytes[(ubicacion.nroByteEntradaSgte)+offset] = 0x80;
	capaDir.sectores[ubicacion.nroSectorEntradaSgte].bytes[(ubicacion.nroByteEntradaSgte)+offset] = 0x80;
	for( uint8_t bytesNombre = 1; bytesNombre < 8; bytesNombre++){
		capaDir.sectores[ubicacion.nroSectorEntradaSgte].bytes[((ubicacion.nroByteEntradaSgte))+bytesNombre] = 0;
	}
	capaDir.sectores[ubicacion.nroSectorEntradaSgte].bytes[((ubicacion.nroByteEntradaSgte))] = 0x80;

	for( uint8_t bytes = 0; bytes < SIZE_ENTRADA_DATA_REGION; bytes++){
		capaDir.sectores[ubicacion.nroSector].bytes[(ubicacion.nroByte)+bytes] = 0;
	}

	for( uint8_t bytes = 0; bytes < SIZE_ENTRADA_DATA_REGION; bytes++){
		capaDir.sectores[ubicacion.nroSectorEntradaSgte].bytes[(ubicacion.nroByteEntradaSgte)+bytes] = 0;
	}

	capaDeDireccionamientoAsectoresEscritura();
	} else {perror("no se pudo borrar la LFN"); exit(7);}
}

UbicacionCache buscarLFNenCacheDireccionamiento(char *bufferNombreLfn){
	//previo llamando de la funcion hay que llamar a capa de direccionamiento
	//para cargar el bloque en donde hay que buscar entrada por entrada la LFN

	uint8_t nroSector;
	UbicacionCache ubicacionEntrada;

	for (nroSector = 0; nroSector < SIZE_CLUSTER; nroSector++){

		uint32_t numByte = 0;

		for( uint32_t nroEntrada = 0; nroEntrada < 16; nroEntrada++){

			uint8_t buffer[32];
			memcpy(&buffer,&capaDir.sectores[nroSector].bytes[numByte],32);
			LFN *entryLfn = NULL;
			entryLfn = (LFN *)malloc(sizeof(LFN));
			castEntryToLfn(buffer,entryLfn);
			//printf("nameLFN: %s \n",buffer.nameLFN1);
			if((entryLfn->attributes == 0x0F)&&(entryLfn->sequenceNumber != 229)){//LFN y recientemente borrada pero libre
				char *bufferLFNarmado;
				bufferLFNarmado = armarNombreLFNaUTF8(*entryLfn);
				if (strcmp(bufferNombreLfn,bufferLFNarmado)== 0) {
					//imprimirLFN(bufferLFNarmado);
					ubicacionEntrada.nroByte = numByte;
					ubicacionEntrada.nroSector = nroSector;
					if( numByte < 480){//cant bytes de la anteultima entrada
						ubicacionEntrada.nroByteEntradaSgte = numByte + 32;
						ubicacionEntrada.nroSectorEntradaSgte = nroSector;
					} else {
						ubicacionEntrada.nroByteEntradaSgte = 0;
						ubicacionEntrada.nroSectorEntradaSgte = nroSector + 1;
					}
					free(bufferLFNarmado);
					free(entryLfn);
					return ubicacionEntrada;
				}
				free(bufferLFNarmado);
			}
			free(entryLfn);
			numByte = numByte + 32;
		}
	}
	ubicacionEntrada.nroByte = 300;//código de error de la función
	ubicacionEntrada.nroSector = 300;
	return ubicacionEntrada;
}

void agregarLfnALista(char *lfn, PtrListaLFN *lista, UbicacionCache ubicacionLfn){

        PtrListaLFN punteroNuevoNodo;
        PtrListaLFN ptrCurrentLista;//se utiliza para guardar la posicion del nodo siguiente al agregar
        PtrListaLFN ptrPreviousLista;//se utiliza para guardar la posicion del nodo anterior al agregar

        punteroNuevoNodo = malloc(sizeof(NodoListaLFN));

        if (punteroNuevoNodo != NULL){
            memcpy(punteroNuevoNodo->lfn,lfn,13);
            punteroNuevoNodo->sectorCache = ubicacionLfn.nroSector;
            punteroNuevoNodo->byteCache = ubicacionLfn.nroByte;
            punteroNuevoNodo->lfnSgte = NULL;
            ptrCurrentLista = *lista;
            ptrPreviousLista = NULL;

            while (ptrCurrentLista != NULL){
                ptrPreviousLista = ptrCurrentLista;
                ptrCurrentLista = ptrCurrentLista->lfnSgte;
            }

            if (ptrPreviousLista == NULL){
                punteroNuevoNodo->lfnSgte = *lista;
                *lista = punteroNuevoNodo;
            }
            else{
                ptrPreviousLista->lfnSgte = punteroNuevoNodo;
            }
        }
        else { printf("No hay memoria disponible!");}
}

void filtrarEntradas(PtrListaLFN *ptrLFN){

	uint16_t nroSector;
	uint32_t offset;
	char *lfn;

	for (nroSector = 0; nroSector < SIZE_BLOCK; nroSector++){

		uint16_t numByte = 0;

		for( uint8_t nroEntrada = 0; nroEntrada < 16; nroEntrada++){

			uint8_t buffer[32];
			memcpy(buffer,&capaDir.sectores[nroSector].bytes[numByte],32);//capaDir se encuentra definida en estructuras.c


			offset = 0x0B;
			if ((buffer[offset] == 0x0F)&&(buffer[0] != 229)) {
				LFN *entryLfn = NULL;
				entryLfn = (LFN *)calloc(1,sizeof(LFN));
				castEntryToLfn(buffer,entryLfn);
				lfn = armarNombreLFNaUTF8(*entryLfn);
				UbicacionCache ubicacionLfn;
				ubicacionLfn.nroSector = nroSector;
				ubicacionLfn.nroByte = numByte;
				agregarLfnALista(lfn,ptrLFN,ubicacionLfn);
				free(entryLfn);
				free(lfn);
			}
			numByte = numByte + 32;
		}
	}
}
